home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 076-100 / scopedisk81 / wkeys / bindwkeys.c < prev    next >
C/C++ Source or Header  |  1995-03-19  |  24KB  |  846 lines

  1. /*
  2.  *  BindWKeys.c     Reads a file and creates an array of key bindings
  3.  *                  to be used by a hot-key handler to tell which keys
  4.  *                  do what.
  5.  *
  6.  *             Copyright (c) 1987,1988 by Davide P. Cervone
  7.  *  You may use this code provided this copyright notice is left intact.
  8.  */
  9.  
  10. #include <exec/types.h>
  11. #include <exec/memory.h>
  12. #include <devices/inputevent.h>
  13. #ifndef NO_FILE
  14. #include <stdio.h>
  15. #endif
  16.  
  17. #include "wKeys.h"
  18.  
  19. #ifndef NO_FILE
  20. #define KEYMASK         0x00FF      /* default qualifier key mask */
  21. #define SHIFT           IECODE_UP_PREFIX
  22.  
  23. #define BADVALUE        -1          /* error while parsing input line */
  24.  
  25. /*
  26.  *  Macros to tell whether a character is printable or not, and
  27.  *  whether it is not alphanumeric
  28.  */
  29. #define PRINTABLE(c)    ((c)>=' '&&(c)<='~')
  30. #define NOTPRINTABLE(c) ((c)<' '||(c)>'~')
  31. #define NOTALPHANUM(c)\
  32.    ((c)<'0'||((c)>'9'&&(c)<'A')||((c)>'Z'&&(c)<'a')||(c)>'z')
  33.  
  34. /*
  35.  *  Create a new instance of a given structure type
  36.  */
  37. #define NEW(s,var)      (var = (struct s *)New("var",sizeof(struct s)))
  38.  
  39. #define LINESIZE    132
  40. static char InputLine[LINESIZE+1];    /* the line read from the file */
  41. static char *CurPos;                  /* current character position in line */
  42. static char *CurWord;                 /* pointer to begining of current word */
  43. static char TerminationChar;          /* character that ended the word */
  44. static int LineCount = 0;             /* number of lines read from the file */
  45. #endif
  46.  
  47. struct HotKeyItem *KeyList = NULL;    /* the list of key definitions so far */
  48. struct HotKey *KeyArray = NULL;       /* the sorted array of key definitions */
  49. int KeyCount = 0;                     /* the number of key definitions */
  50. #define KEYARRAYSIZE    (KeyCount*sizeof(struct HotKey))
  51.  
  52. #ifndef NO_FILE
  53. static FILE *InFile = NULL;           /* the input file */
  54. #define ERROR _OSERR                  /* the system's error variable */
  55. extern int ERROR;
  56.  
  57. /*
  58.  *  This structure maps a character string to a numeric value.  It is used
  59.  *  for mapping key names to keyboard scan codes and key action names to 
  60.  *  action numbers.
  61.  */
  62.  
  63. struct Definition
  64. {
  65.    char *Name;
  66.    UBYTE Code;
  67. };
  68.  
  69. /*
  70.  *  Qualifier[] maps the names of the qualifier keys to their corresponding 
  71.  *  bit positions within the ie_Qualifier field of an InputEvent.  This List 
  72.  *  is sorted by name.  Note that LCOMMAND is equivalent to LAMIGA, etc.  
  73.  *  Note also that there are some compound qualifier names, such as SHIFT.  
  74.  *  These are expanded into more than one key definition.
  75.  *
  76.  *  See devices/inputevent.h for more details on qualifier values.
  77.  */
  78.  
  79. static struct Definition Qualifier[] =
  80. {
  81.    {"ALT",20},
  82.    {"AMIGA",22},
  83.    {"CAPSLOCK",2},
  84.    {"CONTROL",3},
  85.    {"INTERRUPT",10},
  86.    {"KEYUP",31},
  87.    {"LALT",4},
  88.    {"LAMIGA",6},
  89.    {"LBUTTON",14},
  90.    {"LCOMMAND",6},
  91.    {"LSHIFT",0},
  92.    {"MBUTTON",12},
  93.    {"MULTIBROADCAST",11},
  94.    {"NUMERICPAD",8},
  95.    {"RALT",5},
  96.    {"RAMIGA",7},
  97.    {"RBUTTON",13},
  98.    {"RCOMMAND",7},
  99.    {"RELATIVEMOUSE",15},
  100.    {"REPEAT",9},
  101.    {"RSHIFT",1},
  102.    {"SHIFT",16},
  103. };
  104. #define MAXQUALIFIER    (sizeof(Qualifier)/sizeof(struct Definition))
  105.  
  106. /*
  107.  *  AsciiToKeyCode[] maps ASCII characters to keyboard scan-codes.  This array 
  108.  *  is in ASCII order.  SHIFT indicates that one of the shift keys must be 
  109.  *  held down together with the correct key in order to produce that ASCII 
  110.  *  character.  Note, however, that upper- and lower-case letters both are 
  111.  *  mapped to un-shifted keys.
  112.  */
  113.  
  114. static UBYTE AsciiToKeyCode[] =
  115. {
  116.    0x01 | SHIFT,    /* ! */
  117.    0x2A | SHIFT,    /* " */
  118.    0x03 | SHIFT,    /* # */
  119.    0x04 | SHIFT,    /* $ */
  120.    0x05 | SHIFT,    /* % */
  121.    0x07 | SHIFT,    /* & */
  122.    0x2A,            /* ' */
  123.    0x09 | SHIFT,    /* ( */
  124.    0x0A | SHIFT,    /* ) */
  125.    0x08 | SHIFT,    /* * */
  126.    0x0C | SHIFT,    /* + */
  127.    0x38,            /* , */
  128.    0x0B,            /* - */
  129.    0x39,            /* . */
  130.    0x3A,            /* / */
  131.    0x0A,            /* 0 */
  132.    0x01,            /* 1 */
  133.    0x02,            /* 2 */
  134.    0x03,            /* 3 */
  135.    0x04,            /* 4 */
  136.    0x05,            /* 5 */
  137.    0x06,            /* 6 */
  138.    0x07,            /* 7 */
  139.    0x08,            /* 8 */
  140.    0x09,            /* 9 */
  141.    0x29 | SHIFT,    /* : */
  142.    0x29,            /* ; */
  143.    0x38 | SHIFT,    /* < */
  144.    0x0C,            /* = */
  145.    0x39 | SHIFT,    /* > */
  146.    0x3A | SHIFT,    /* ? */
  147.    0x02 | SHIFT,    /* @ */
  148.    0x20,            /* A */
  149.    0x35,            /* B */
  150.    0x33,            /* C */
  151.    0x22,            /* D */
  152.    0x12,            /* E */
  153.    0x23,            /* F */
  154.    0x24,            /* G */
  155.    0x25,            /* H */
  156.    0x17,            /* I */
  157.    0x26,            /* J */
  158.    0x27,            /* K */
  159.    0x28,            /* L */
  160.    0x37,            /* M */
  161.    0x36,            /* N */
  162.    0x18,            /* O */
  163.    0x19,            /* P */
  164.    0x10,            /* Q */
  165.    0x13,            /* R */
  166.    0x21,            /* S */
  167.    0x14,            /* T */
  168.    0x16,            /* U */
  169.    0x34,            /* V */
  170.    0x11,            /* W */
  171.    0x32,            /* X */
  172.    0x15,            /* Y */
  173.    0x31,            /* Z */
  174.    0x1A,            /* [ */
  175.    0x0D | SHIFT,    /* \ */
  176.    0x1B,            /* ] */
  177.    0x06 | SHIFT,    /* ^ */
  178.    0x0B | SHIFT,    /* _ */
  179.    0x00,            /* ` */
  180.    0x20,            /* a */
  181.    0x35,            /* b */
  182.    0x33,            /* c */
  183.    0x22,            /* d */
  184.    0x12,            /* e */
  185.    0x23,            /* f */
  186.    0x24,            /* g */
  187.    0x25,            /* h */
  188.    0x17,            /* i */
  189.    0x26,            /* j */
  190.    0x27,            /* k */
  191.    0x28,            /* l */
  192.    0x37,            /* m */
  193.    0x36,            /* n */
  194.    0x18,            /* o */
  195.    0x19,            /* p */
  196.    0x10,            /* q */
  197.    0x13,            /* r */
  198.    0x21,            /* s */
  199.    0x14,            /* t */
  200.    0x16,            /* u */
  201.    0x34,            /* v */
  202.    0x11,            /* w */
  203.    0x32,            /* x */
  204.    0x15,            /* y */
  205.    0x31,            /* z */
  206.    0x1A | SHIFT,    /* { */
  207.    0x0D | SHIFT,    /* | */
  208.    0x1B | SHIFT,    /* } */
  209.    0x00 | SHIFT,    /* ~ */
  210. };
  211. #define MAXASCII    sizeof(AsciiToKeyCode)
  212.  
  213. /*
  214.  *  Key[] maps key names to their keyboard scan-codes.  This array is sorted
  215.  *  by name.  SHIFT means that a SHIFT key must be held down in addition to
  216.  *  the indicated key.  Some keys have more than one name (e.g., ESCAPE is
  217.  *  equivalent to ESC).  Note that pressing a qualifier key also can be
  218.  *  detected.
  219.  */
  220.  
  221. static struct Definition Key[] =
  222. {
  223.    {"BACKSPACE",0x41},
  224.    {"BS", 0x41},
  225.    {"CAPSLOCKKEY",0x62},
  226.    {"COLON",0x29 | SHIFT},
  227.    {"COMMA",0x38},
  228.    {"CONTROLKEY",0x63},
  229.    {"DASH",0x0B},
  230.    {"DEL",0x46},
  231.    {"DELETE",0x46},
  232.    {"DOT",0x3C},
  233.    {"DOWNARROW",0x4D},
  234.    {"ENTER",0x42},
  235.    {"ESC",0x45},
  236.    {"ESCAPE",0x45},
  237.    {"F1",0x50},
  238.    {"F10",0x59},
  239.    {"F2",0x51},
  240.    {"F3",0x52},
  241.    {"F4",0x53},
  242.    {"F5",0x54},
  243.    {"F6",0x55},
  244.    {"F7",0x56},
  245.    {"F8",0x57},
  246.    {"F9",0x58},
  247.    {"HELP",0x5F},
  248.    {"KP0",0x0F},
  249.    {"KP1",0x1D},
  250.    {"KP2",0x1E},
  251.    {"KP3",0x1F},
  252.    {"KP4",0x2D},
  253.    {"KP5",0x2E},
  254.    {"KP6",0x2F},
  255.    {"KP7",0x3D},
  256.    {"KP8",0x3E},
  257.    {"KP9",0x3F},
  258.    {"LALTKEY",0x64},
  259.    {"LAMIGAKEY",0x66},
  260.    {"LCOMMANDKEY",0x66},
  261.    {"LEFTARROW",0x4F},
  262.    {"LSHIFTKEY",0x60},
  263.    {"MINUS",0x4A},
  264.    {"RALTKEY",0x65},
  265.    {"RAMIGAKEY",0x67},
  266.    {"RCOMMANDKEY",0x67},
  267.    {"RETURN",0x44},
  268.    {"RIGHTARROW",0x4E},
  269.    {"RSHIFTKEY",0x61},
  270.    {"SPACE",0x40},
  271.    {"TAB",0x42},
  272.    {"UPARROW",0x4C},
  273. };
  274. #define MAXKEY      (sizeof(Key)/sizeof(struct Definition)) 
  275.  
  276. /*
  277.  *  Action[] maps key action names to their action numbers (used by the
  278.  *  input handler to perform the action when the key is pressed).  This array
  279.  *  is sorted by name.
  280.  */
  281.  
  282. static struct Definition Action[] =
  283. {
  284.    {"BACK-WINDOW-TO-FRONT", BACKTOFRONT},
  285.    {"CLOSE-WINDOW",         CLOSETHEWINDOW},
  286.    {"FRONT-WINDOW-TO-BACK", FRONTTOBACK},
  287.    {"ICON-TO-WINDOW",       ICONTOWINDOW},
  288.    {"NEXT-WINDOW",          ACTIVATENEXT},
  289.    {"PREVIOUS-WINDOW",      ACTIVATEPREVIOUS},
  290.    {"SCREEN-TO-BACK",       SCREENTOBACK},
  291.    {"SCREEN-TO-FRONT",      SCREENTOFRONT},
  292.    {"SELECT-NEXT-ICON",     SELECTNEXTICON},
  293.    {"WINDOW-TO-BACK",       WINDOWTOBACK},
  294.    {"WINDOW-TO-FRONT",      WINDOWTOFRONT},
  295.    {"WINDOW-TO-ICON",       WINDOWTOICON},
  296. };
  297. #define MAXACTION   (sizeof(Action)/sizeof(struct Definition))
  298. #endif
  299.  
  300. /*
  301.  *  Some shorthand macros used to define the default key layout
  302.  */
  303.  
  304. #define RAMIGA      IEQUALIFIER_RCOMMAND
  305. #define RSHIFT      IEQUALIFIER_RSHIFT
  306.  
  307. #define UPARROW     0x4C
  308. #define DOWNARROW   0x4D
  309. #define RIGHTARROW  0x4E
  310. #define LEFTARROW   0x4F
  311. #define BSKEY       0x41
  312. #define TABKEY      0x42
  313. #define RETURNKEY   0x44
  314. #define DELETEKEY   0x46
  315.  
  316. #define HOTKEY(q,c,a)  {{c,0,q},{0xFF,a,RAMIGA|RSHIFT}}
  317.  
  318. /*
  319.  *  DefaultKey[] maps the default key layout.  This array is sorted by
  320.  *  KeyCode value.  Change this array to change the default key bindings.
  321.  */
  322.  
  323. static struct HotKey DefaultKey[] =
  324. {
  325.    HOTKEY(          RAMIGA, BSKEY,      ICONTOWINDOW),
  326.    HOTKEY(          RAMIGA, TABKEY,     SELECTNEXTICON),
  327.    HOTKEY(          RAMIGA, RETURNKEY,  WINDOWTOICON),
  328.    HOTKEY(          RAMIGA, DELETEKEY,  CLOSETHEWINDOW),
  329.    HOTKEY(          RAMIGA, UPARROW,    WINDOWTOFRONT),
  330.    HOTKEY( RSHIFT | RAMIGA, UPARROW,    SCREENTOFRONT),
  331.    HOTKEY(          RAMIGA, DOWNARROW,  WINDOWTOBACK),
  332.    HOTKEY( RSHIFT | RAMIGA, DOWNARROW,  SCREENTOBACK),
  333.    HOTKEY(          RAMIGA, RIGHTARROW, ACTIVATENEXT),
  334.    HOTKEY( RSHIFT | RAMIGA, RIGHTARROW, FRONTTOBACK),
  335.    HOTKEY(          RAMIGA, LEFTARROW,  ACTIVATEPREVIOUS),
  336.    HOTKEY( RSHIFT | RAMIGA, LEFTARROW,  BACKTOFRONT),
  337. };
  338. #define DEFAULTSIZE (sizeof(DefaultKey)/sizeof(struct HotKey))
  339.  
  340. #ifndef NO_FILE
  341. /*
  342.  *  Error()
  343.  *
  344.  *  Print an error message and the line number where the error occured.
  345.  *  Return the error value.
  346.  */
  347.  
  348. static int Error(s,x1,x2,x3)
  349. char *s, *x1,*x2,*x3;
  350. {
  351.    printf("Line %2d:  ",LineCount);
  352.    printf(s,x1,x2,x3);
  353.    printf("\n");
  354.    return(BADVALUE);
  355. }
  356.  
  357. /*
  358.  *  GetNextWord()
  359.  *
  360.  *  Isolate the next word in the line read from the file.
  361.  *  If we are not at the end of the line, then
  362.  *    skip over leading spaces,
  363.  *    set CurWord to point to the beginning of the word,
  364.  *    while we are not at the end of the word,
  365.  *      check if the current character is a word delimiter:
  366.  *      if it is a space or a tab,
  367.  *        skip additional spaces or tabs,
  368.  *        set the terminator character,
  369.  *        and end the word.  
  370.  *        (At this point, CurPos will be pointing to the "real" delimiter,
  371.  *        or to the beginning of the next word, if the delimiter really was
  372.  *        a space).
  373.  *      if it was a NULL, convert it to a new-line.
  374.  *      if it was a dash, comma, colon or new-line,
  375.  *        save the termination character for later,
  376.  *        replace the charactger with a NULL so that CurWord will end at
  377.  *          the end of the word,
  378.  *        and stop looking for more of the word.
  379.  *      otherwise
  380.  *       if we're still looking for the end of the word (i.e., we have not
  381.  *         ended, it by hitting a space),
  382.  *         if its unprintable or the current word is more than one character
  383.  *           long and the current character is not alphanumeric,
  384.  *           then record the bad character and end the word
  385.  *         go on to the next character (i.e., add the current one to the word)
  386.  */
  387.  
  388. static void GetNextWord()
  389. {
  390.    short NotDone = TRUE;
  391.    char c;
  392.  
  393.    if (TerminationChar != '\n')
  394.    {
  395.       while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
  396.       CurWord = CurPos;
  397.       while (NotDone)
  398.       {
  399.          if (*CurPos == ' ' || *CurPos == '\t')
  400.          {
  401.             *CurPos = '\0';
  402.             while (*(++CurPos) == ' ' || *CurPos == '\t');
  403.             TerminationChar = ' ';
  404.             NotDone = FALSE;
  405.          }
  406.          switch(c = *CurPos)
  407.          {
  408.             case '\0':
  409.                c = *CurPos = '\n';
  410.             case '-':
  411.             case ',':
  412.             case ':':
  413.             case '\n':
  414.                TerminationChar = c;
  415.                *CurPos++ = '\0';
  416.                NotDone = FALSE;
  417.                break;
  418.  
  419.             default:
  420.                if (NotDone)
  421.                {
  422.                   if (NOTPRINTABLE(c) || (CurPos != CurWord && NOTALPHANUM(c)))
  423.                   {
  424.                      TerminationChar = c;
  425.                      NotDone = FALSE;
  426.                   }
  427.                   CurPos++;
  428.                }
  429.                break;
  430.          }
  431.       }
  432.    }
  433. }
  434.  
  435. /*
  436.  *  FindWord()
  437.  *
  438.  *  Search the KeyWord array (containing Count entries) for an entry with
  439.  *  Name equal to theWord.  Return the corresponding Code value, or BADVALUE
  440.  *  if theWord does not appear in the KeyWord array.
  441.  *
  442.  *  KeyWord[] must be sorted by name, since we use a binary search to find
  443.  *  theWord witin it.
  444.  */
  445.  
  446. static int FindWord(theWord,KeyWord,Count)
  447. char *theWord;
  448. struct Definition KeyWord[];
  449. int Count;
  450. {
  451.    int value = BADVALUE;
  452.    register short Min,Max, Num;
  453.    register int comp;
  454.    
  455.    Max = Count; Min = -1;
  456.    while ((Num = (Min + Max) >> 1) != Min && value == BADVALUE)
  457.    {
  458.       comp = stricmp(theWord,KeyWord[Num].Name);
  459.       if (comp < 0) Max = Num; else if (comp > 0) Min = Num;
  460.          else value = KeyWord[Num].Code;
  461.    }
  462.    return(value);
  463. }
  464.  
  465. /*
  466.  *  FindQualifier()
  467.  *
  468.  *  Find a qualifier name in the Qualifier[] array.
  469.  */
  470. #define FindQualifier(w)    FindWord(w,Qualifier,MAXQUALIFIER)
  471.  
  472. /*
  473.  *  FindKeyCode()
  474.  *
  475.  *  Find the scan-code for the given key name.  If the key name is a single
  476.  *  ASCII character, use the AsciiToKeyCode array to look up the scan-code
  477.  *  directly, otherwise use FindWord() to search the Key[] array.
  478.  */
  479.  
  480. static int FindKeyCode(theWord)
  481. char *theWord;
  482. {
  483.    int value = BADVALUE;
  484.    
  485.    if (strlen(theWord) == 1)
  486.    {
  487.       if (PRINTABLE(*theWord)) value = AsciiToKeyCode[*theWord-'!'];
  488.    } else {
  489.       value = FindWord(theWord,Key,MAXKEY);
  490.    }
  491.    return(value);
  492. }
  493.  
  494. /*
  495.  *  GetKeyCode()
  496.  *
  497.  *  Parse a set of qualifiers and a key name and return the KeyCode longword
  498.  *  that describes the designated key.  SHIFT, AMIGA, and ALT flags are 
  499.  *  used to indicate when more than one key is designated.  Return BADVALUE
  500.  *  if there is an error parsing the line.
  501.  *
  502.  *  Get the next word on the line, and check the termination character.  
  503.  *  Qualifiers end with dashes, commas, or spaces; key-names end with a colon.
  504.  *  Try to find the qualifier or key-name in the proper list, and give an error
  505.  *  if it can not be found, or if the name is null.  For a qualifier, set its
  506.  *  flag bit in the KeyCode longword.  For key-names, set the scan-code and
  507.  *  the set the SHIFT bit in the qualifier flag bits if necessary.
  508.  *  If the end of the line is reached, display an error.  If some other
  509.  *  delimiter was found, then display an error (making unprintable characters
  510.  *  printable).
  511.  *
  512.  *  Once a key-name is found, stop looking for more words.
  513.  */
  514.  
  515. static void GetKeyCode(theKey)
  516. long *theKey;
  517. {
  518.    short NotDone = TRUE;
  519.    int value;
  520.  
  521.    *theKey = 0;
  522.    while (NotDone)
  523.    {
  524.       GetNextWord();
  525.       switch(TerminationChar)
  526.       {
  527.          case '-':
  528.          case ',':
  529.          case ' ':
  530.             if (strlen(CurWord))
  531.             {
  532.                value = FindQualifier(CurWord);
  533.                if (value > BADVALUE)
  534.                   *theKey |= (1 << value);
  535.                  else
  536.                   *theKey = Error("Unrecognized key qualifier '%s'",CurWord);
  537.             } else {
  538.                *theKey = Error("Missing qualifier keyword");
  539.             }
  540.             break;
  541.  
  542.          case ':':
  543.             if (strlen(CurWord))
  544.             {
  545.                value = FindKeyCode(CurWord);
  546.                if (value > BADVALUE)
  547.                {
  548.                   *theKey |= ((value & (~SHIFT)) << 24) |
  549.                              ((value & SHIFT) << 9);
  550.                } else {
  551.                   *theKey = Error("Unrecognized key name '%s'",CurWord);
  552.                }
  553.             } else {
  554.                *theKey = Error("Key name not specified");
  555.             }
  556.             NotDone = FALSE;
  557.             break;
  558.  
  559.          case '\n':
  560.             *theKey = Error("Key name ends prematurely");
  561.             NotDone = FALSE;
  562.             break;
  563.  
  564.          default:
  565.             if ((TerminationChar & 0x7F) >= ' ')
  566.                *theKey = Error("Illegal delimiter character '%c'",
  567.                   (char)TerminationChar);
  568.               else
  569.                *theKey = Error("Illegal delimiter character '^%c'",
  570.                   (char)((TerminationChar & 0x7F) + '@'));
  571.             break;
  572.       }
  573.    }
  574. }
  575.  
  576. /*
  577.  *  GetKeyAction()
  578.  *
  579.  *  Parse the rest of the input line for a key-action keyword.  First, remove
  580.  *  leading and training blanks, and replace the final new-line with a NULL.
  581.  *  Look up the remainder of the line (if any) in the Action[] array, and
  582.  *  if it is not found, report the error.
  583.  */
  584.  
  585. static void GetKeyAction(theAction)
  586. short *theAction;
  587. {
  588.    *theAction = BADVALUE;
  589.  
  590.    while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
  591.    CurWord = CurPos;
  592.    CurPos = CurPos + strlen(CurWord) - 1;
  593.    if (*CurPos == '\n') *CurPos-- = '\0';
  594.    while (*CurPos == ' ' || *CurPos == '\t') *CurPos-- = '\0';
  595.  
  596.    if (*CurWord)
  597.    {
  598.       *theAction = FindWord(CurWord,Action,MAXACTION);
  599.       if (*theAction == BADVALUE) Error("Unrecognized action '%s'",CurWord);
  600.    } else {
  601.       Error("No action specified");
  602.    }
  603. }
  604.  
  605. /*
  606.  *  KeyCompare()
  607.  *
  608.  *  Return a positive number if the first key is bigger than the second,
  609.  *  zero if they are equal, and a negative number if the second key is 
  610.  *  bigger.  This routine is used by mSort() to sort the keys.
  611.  */
  612.  
  613. static int KeyCompare(key1,key2)
  614. struct HotKeyItem *key1, *key2;
  615. {
  616.    return(key1->hki_KeyCode - key2->hki_KeyCode);
  617. }
  618.  
  619. /*
  620.  *
  621.  *  KeyDispose()
  622.  *
  623.  *  Remove a duplicate key definition and report the fact that a key is
  624.  *  multiply defined (it takes a little work to get the qualifier and key
  625.  *  names back out of the arrays).  This routine is called by mSort() when
  626.  *  it finds duplicate keys.
  627.  */
  628.  
  629. static void KeyDispose(key)
  630. struct HotKeyItem *key;
  631. {
  632.    short i;
  633.    UBYTE code = key->hki_Code & 0x7F;
  634.    int KeyNotFound = TRUE;
  635.    long mask = 0xFFFFFFFF;
  636.  
  637.    printf("Key ");
  638.    for (i=0; i<MAXQUALIFIER; i++)
  639.       if (key->hki_KeyCode & (1 << Qualifier[i].Code) & mask)
  640.       {
  641.          printf("%s-",Qualifier[i].Name);
  642.          mask &= ~(1 << Qualifier[i].Code);
  643.       }
  644.    for (i=0; i<MAXKEY && KeyNotFound; i++)
  645.       if (code == Key[i].Code)
  646.       {
  647.          printf("%s",Key[i].Name);
  648.          KeyNotFound = FALSE;
  649.       }
  650.    for (i=0; i<MAXASCII && KeyNotFound; i++)
  651.    {
  652.       if (code == AsciiToKeyCode[i])
  653.       {
  654.          printf("%c",i+'!');
  655.          KeyNotFound = FALSE;
  656.       }
  657.    }
  658.    printf(" multiply defined\n");
  659.    KeyCount--;
  660.    key->Next = key->Prev = NULL;
  661.    FreeMem(key,sizeof(*key));
  662. }
  663.  
  664. /*
  665.  *  GetKeyList()
  666.  *
  667.  *  Read each line from the file (incrementing the line count as we go), 
  668.  *  and skip leading spaces and blank lines.  Get the key code and key action
  669.  *  specified on the line.  If no error was found, add the key definition 
  670.  *  to the linked list of keys defined.  If SHIFT, AMIGA, or ALT were specified,
  671.  *  then add one key each for the left and right version of that qualifier.
  672.  */
  673.  
  674. static void GetKeyList()
  675. {
  676.    long theKey;
  677.    short theAction;
  678.    struct HotKeyItem *TempKey;
  679.    UWORD mask,multikeys;
  680.    extern char *fgets();
  681.  
  682.    while (feof(InFile) == FALSE)
  683.    {
  684.       CurPos = fgets(InputLine,LINESIZE,InFile);
  685.       TerminationChar = '\0';
  686.       LineCount++;
  687.       while (*CurPos == ' ' || *CurPos == '\t') CurPos++;
  688.  
  689.       if (CurPos != NULL && *CurPos != '\0' && *CurPos != '\n')
  690.       {
  691.          GetKeyCode(&theKey);
  692.          GetKeyAction(&theAction);
  693.          if (theKey != BADVALUE && theAction != BADVALUE)
  694.          {
  695.             multikeys = (theKey >> 15) & 0xFE;
  696.             multikeys |= multikeys << 1;
  697.             if (multikeys == 0) multikeys = 1;
  698.             for (mask=1; multikeys; mask<<=1,multikeys>>=1)
  699.             {
  700.                if (multikeys & 1)
  701.                {
  702.                   NEW(HotKeyItem,TempKey);
  703.                   TempKey->hki_KeyCode = theKey;
  704.                   TempKey->hki_Flags   = 0;
  705.                   TempKey->hki_Qual   |= mask >> 1;
  706.                   TempKey->hki_KeyMask = 0xFFFFFFFF;
  707.                   TempKey->hki_Action  = theAction;
  708.                   TempKey->Next = KeyList;
  709.                   KeyList = TempKey;
  710.                   KeyCount++;
  711.                }
  712.             }
  713.          }
  714.       }
  715.    }
  716. }
  717.  
  718. /*
  719.  *  SetKeyMasks()
  720.  *
  721.  *  For each key scan-code, we OR together the qualifier masks for all the
  722.  *  definitions for that scan-code and set the key Mask value for each
  723.  *  key with that scan-code to the final ORed mask.  That is, the Mask value
  724.  *  indicates what qualifiers are important for determining when a key has
  725.  *  been pressed (and distinguishing it from other definitions using the
  726.  *  same scan-code but different qualifiers).
  727.  */
  728.  
  729. static void SetKeyMasks()
  730. {
  731.    struct HotKeyItem *CurKey = KeyList;
  732.    struct HotKeyItem *LastKey = CurKey;
  733.    UWORD Mask;
  734.  
  735.    while (LastKey)
  736.    {
  737.       Mask = 0;
  738.       while (CurKey && CurKey->hki_Code == LastKey->hki_Code)
  739.       {
  740.          Mask |= CurKey->hki_Qual;
  741.          CurKey = CurKey->Next;
  742.       }
  743.       if (Mask == 0) Mask = KEYMASK;
  744.       do
  745.       {
  746.          LastKey->hki_Mask = Mask;
  747.          LastKey = LastKey->Next;
  748.       } while (LastKey != CurKey);
  749.    }
  750. }
  751.  
  752. /*
  753.  *  MakeKeyArray()
  754.  *
  755.  *  If there are any keys defined, allocate enough space for the KeyArray
  756.  *  that will contain the key definitions, then go through the list and
  757.  *  copy the definitions into the array.  Free each item from the list once it
  758.  *  is copied.  The array saves space (it does not need to contain pointers 
  759.  *  to next and previous items), and allows for easy implementation of a 
  760.  *  binary search on the array.
  761.  */
  762.  
  763. static void MakeKeyArray()
  764. {
  765.    struct HotKeyItem *TempKey;
  766.    short i;
  767.  
  768.    if (KeyCount)
  769.    {
  770.       KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE);
  771.       for (i=0; i<KeyCount; i++)
  772.       {
  773.          KeyArray[i].hk_KeyCode = KeyList->hki_KeyCode;
  774.          KeyArray[i].hk_KeyMask = KeyList->hki_KeyMask;
  775.          TempKey = KeyList; KeyList = KeyList->Next;
  776.          FreeMem(TempKey,sizeof(*TempKey));
  777.       }
  778.    }
  779. }
  780. #endif
  781.  
  782. /*
  783.  *  MakeDefaultArray()
  784.  *
  785.  *  Copy the DefaultKey[] array into a dynamically allocated array that can
  786.  *  be passed to the input handler and still remain in memory even when the
  787.  *  original process is unloaded.
  788.  */
  789.  
  790. static void MakeDefaultArray()
  791. {
  792.    short i;
  793.    
  794.    KeyCount = DEFAULTSIZE;
  795.    KeyArray = (struct HotKey *)New("KeyArray",KEYARRAYSIZE);
  796.    for (i=0; i<KeyCount; i++)
  797.    {
  798.       KeyArray[i].hk_KeyCode = DefaultKey[i].hk_KeyCode;
  799.       KeyArray[i].hk_KeyMask = DefaultKey[i].hk_KeyMask;
  800.    }
  801. }
  802.  
  803. /*
  804.  *  GetKeyArray()
  805.  *
  806.  *  If there is a command-line argument, then 
  807.  *    it must be a file name, so try to open it (error if there is a problem).
  808.  *    Create the key definition list from the lines in the file.
  809.  *    If there were no valid key definitions, 
  810.  *      say so,
  811.  *     otherwise, 
  812.  *      sort the key list,
  813.  *      set the key masks for each scan-code,
  814.  *      make the key array from the sorted list.
  815.  *   otherwise (there was no file name given, so)
  816.  *    make the key array from the default key list.
  817.  */
  818.  
  819. void GetKeyArray(argc,argv)
  820. int argc;
  821. char *argv[];
  822. {
  823. #ifndef NO_FILE
  824.    extern struct HotKeyItem *mSort(); 
  825.  
  826.    if (argc > 1)
  827.    {
  828.       InFile = fopen(argv[1],"r");
  829.       if (InFile == NULL)
  830.          DoExit("Can't Open File '%s':  Error %d",argv[1],ERROR);
  831.       GetKeyList();
  832.       if (KeyCount == 0)
  833.       {
  834.          DoExit("No valid key definitions found in file '%s'",argv[1]);
  835.       } else {
  836.          KeyList = mSort(KeyList,KeyCompare,KeyDispose);
  837.          SetKeyMasks();
  838.          MakeKeyArray();
  839.       }
  840.    } else
  841. #endif
  842.    {
  843.       MakeDefaultArray();
  844.    }
  845. }
  846.